#include "CNode.h"
#include "..\\CLayer.h"
#include "..\\Messaging\CSGP_EventSystem.h"
#include "CTeleporter.h"
#include "CEnemy.h"
#include "CPlayer.h"
#include "..\COptionsState.h"
#include "..\\Wrappers\\CSGD_TextureManager.h"
#include "..\\Wrappers\\CSGD_Direct3D.h"
#include "..\\Wrappers\\CSGD_DirectInput.h"
#include "..\\Wrappers\\CSGD_FModManager.h"
#include "..\\ObjectManager.h"
#include "CCamera.h"
#include "CWorm.h"
#include "CTurret.h"
#include "CSpider.h"
#include "..\\CAI.h"
#include "..\\Firewall.h"
#include "..\CDoor.h"
#include "..\console.h"
CNode::CNode()
{
	numEnemiesEffect = 0;
	CSGP_EventSystem::GetInstance()->RegisterClient("enemy.death", this);
	CSGP_EventSystem::GetInstance()->RegisterClient("num.enemies", this);
	ai = NULL;

	m_nTeleportID = CSGD_FModManager::GetInstance()->LoadSound("Resource/Sound/SGP_Teleport.wav");
	CSGD_FModManager::GetInstance()->SetVolume(m_nTeleportID, COptionsState::GetInstance()->GetSFXVolume());

	isActive = false;
}

CNode::~CNode()
{
	// Clear the memory for the master list of enemies
	for(unsigned int i = 0; i < enemies.size(); ++i)
		delete enemies[i];

	// Clear the memory for the layers
	for(unsigned int i = 0; i < layers.size(); i++)
		delete layers[i];

	// Clear the memory for the teleporters 
	for(unsigned int i = 0; i < teleporters.size(); ++i)
		delete teleporters[i];
	for(unsigned int i = 0; i < doors.size(); ++i)
		delete doors[i];

	for(unsigned int i = 0; i < consoles.size(); ++i)
		delete consoles[i];

	for(unsigned int i = 0; i < firewalls.size(); ++i)
		delete firewalls[i];
	CSGP_EventSystem::GetInstance()->UnregisterClient("enemy.death", this);
	CSGP_EventSystem::GetInstance()->UnregisterClient("num.enemies", this);
}

void CNode::PushEnemy(const CEnemy* const pEnemy)
{
	// Allocate memory for the passed enemy and add to the master list
	switch(pEnemy->GetType())
	{
	case CBase::OBJ_TURRET:{
		CTurret* temp = new CTurret(*(CTurret*)pEnemy);
		enemies.push_back(temp);
		}break;
	case CBase::OBJ_SPIDER:{
		CSpider* temp = new CSpider(*(CSpider*)pEnemy);
		enemies.push_back(temp);
		}break;
	case CBase::OBJ_WORM:{
		CWorm* temp = new CWorm(*(CWorm*)pEnemy);
		enemies.push_back(temp);
		}break;
	case CBase::OBJ_FIREWALL:{
		CFirewall* temp = new CFirewall(*(CFirewall*)pEnemy);
		temp->play(temp);
		firewalls.push_back(temp);
		}break;
	}
}

void CNode::PushDoor(const CDoor* const pDoor)
{
	CDoor* temp = new CDoor(*pDoor);
	doors.push_back(temp);
}
void CNode::PushConsole(const console* const pconsole)
{
	console* temp = new console(*pconsole);
	consoles.push_back(temp);
}

void CNode::PushLayer( CLayer*  pLayer)
{
	// Allocate memory for the passed layer and add to the list
	CLayer* temp = new CLayer(*pLayer);
	layers.push_back(temp);
}

void CNode::PushTeleporter(const CTeleporter* const pTeleporter)
{
	// Allocate memory for the passed layer and add to the list
	CTeleporter* temp = new CTeleporter(*pTeleporter);
	teleporters.push_back(temp);
}

void CNode::SetOwner(OWNER newOwner)
{
	OWNER oldOwner = owner;
	// Change the owner
	owner = newOwner;

	// if the new owner is the player
	if(owner == OWNER_PLAYER)
	{
		// Let everyone listening that the player captured this point
		CSGP_EventSystem::GetInstance()->SendEvent("player.capture", this);

		// Open up all of the teleporters in this node
		for(unsigned int i = 0; i < teleporters.size(); ++i)
			teleporters[i]->Activate();

		// Handle applying positive effects
		switch(effect)
		{
		case N_EFFECT_SPEED:
			if(oldOwner == OWNER_AI)
				CPlayer::GetInstance()->SetSpeedFactor(CPlayer::GetInstance()->GetSpeedFactor() + 0.5f);
			else
				CPlayer::GetInstance()->SetSpeedFactor(CPlayer::GetInstance()->GetSpeedFactor() + 0.25f);
			break;
		case N_EFFECT_CAP_RATE:
			if(ai)
			{
				if(oldOwner == OWNER_AI)
					ai->SetRate(ai->GetRate() * 1.15f * 1.15f);
				else
					ai->SetRate(ai->GetRate() * 1.15f);
			}
			break;
		case N_EFFECT_MONEY:
			if(oldOwner == OWNER_AI)
				CPlayer::GetInstance()->SetMoneyFactor(CPlayer::GetInstance()->GetMoneyFactor() + 0.5f);
			else
				CPlayer::GetInstance()->SetMoneyFactor(CPlayer::GetInstance()->GetMoneyFactor() + 0.25f);
			break;
		
		}

	}
	// if the new owner is the AI
	else if(owner == OWNER_AI)
	{
		// Let everyone listening that the AI captured this point
		CSGP_EventSystem::GetInstance()->SendEvent("ai.capture", this);

		// Close all of the teleporters that are connected to nodes that the player doesn't own.
		for(unsigned int i = 0; i < teleporters.size(); ++i)
			teleporters[i]->DeActivate();

		SpawnEnemies();

		// Handle applying negative effects
		switch(effect)
		{
		case N_EFFECT_SPEED:
			if(oldOwner == OWNER_PLAYER)
				CPlayer::GetInstance()->SetSpeedFactor(CPlayer::GetInstance()->GetSpeedFactor() - 0.5f);
			else
				CPlayer::GetInstance()->SetSpeedFactor(CPlayer::GetInstance()->GetSpeedFactor() - 0.25f);
			break;
		case N_EFFECT_CAP_RATE:
			if(ai)
			{
				if(oldOwner == OWNER_PLAYER)
					ai->SetRate(ai->GetRate() / 1.15f / 1.15f);
				else
					ai->SetRate(ai->GetRate() / 1.15f);
			}
			break;
		case N_EFFECT_MONEY:
			if(oldOwner == OWNER_PLAYER)
				CPlayer::GetInstance()->SetMoneyFactor(CPlayer::GetInstance()->GetMoneyFactor() - 0.5f);
			else
				CPlayer::GetInstance()->SetMoneyFactor(CPlayer::GetInstance()->GetMoneyFactor() - 0.25f);
			break;
		
		}
	}
}

void CNode::SpawnEnemies()
{
	// Clear the active list of enemies
	activeEnemies.clear();

	// Loop through the master list of enemies
	for(unsigned int i = 0; i < enemies.size(); ++i)
	{
		// Reset the enemy
		enemies[i]->Reset();
			
		// Add the enemy to the active list
		activeEnemies.push_back(enemies[i]);
	}
}

void CNode::FlushEnemies()
{
	for(unsigned int i = 0; i < activeEnemies.size(); ++i)
		ObjectManager::GetInstance()->RemoveObject(activeEnemies[i]);

	SpawnEnemies();

	for(unsigned int i = 0; i < activeEnemies.size(); ++i)
		ObjectManager::GetInstance()->AddObject(activeEnemies[i]);
}

void CNode::Update(float fElapsedTime)
{	
	// Check to see if the player is trying to teleport
	if(CSGD_DirectInput::GetInstance()->KeyPressedEx(DIK_SPACE)|| CSGD_DirectInput::GetInstance()->JoystickButtonReleased(0))
	{
		// Assign comparison variables for optimization
		RECT playerRect = CPlayer::GetInstance()->GetCollisionRect();

		// Loop through all of the teleporters in this Node
		for(unsigned int i = 0; i < teleporters.size(); ++i)
		{
			RECT teleRect;
			teleRect.left = (long)teleporters[i]->GetPosX();
			teleRect.right = teleRect.left + teleporters[i]->GetWidth();
			teleRect.top = (long)teleporters[i]->GetPosY();
			teleRect.bottom = teleRect.top + teleporters[i]->GetHeight();
			// Check to see if the teleporter is in range of the player
			if(playerRect.right > teleRect.left && playerRect.left < teleRect.right &&
				playerRect.bottom > teleRect.top && playerRect.top < teleRect.bottom)
			{
				CSGD_FModManager::GetInstance()->PlaySound(m_nTeleportID);
				teleporters[i]->Teleport();
				return;
			}
		}
	}
	
	// if there are no more enemies left in the node, the player has captured it.
	if(!activeEnemies.size() && GetOwner() != OWNER_PLAYER)
		SetOwner(OWNER_PLAYER);
}

void CNode::Render()
{
	RECT camRect = CCamera::GetInstance()->GetCameraRect();
	int camOffsetX = CCamera::GetInstance()->GetOffsetX();
	int camOffsetY = CCamera::GetInstance()->GetOffsetY();


	std::vector<CTile*>* tiless = layers[0]->GetTiles();
	int tileWidth = tiless->operator[](0)->GetWidth();
	int tileHeight = tiless->operator[](0)->GetHeight();
	//int screenWidth = CCamera::GetInstance()->GetScreenWidth();
	//int screenHeight = CCamera::GetInstance()->GetScreenHeight();
	
	
	for(unsigned int i = 0; i < layers.size(); i++)
	{
		std::vector<CTile*>* tiles = layers[i]->GetTiles();
		int temp = tiles->size();
		
		for(int j = 0; j < temp; j++)
		{
			RECT offset;
			offset.top = (tiles->operator[](j)->GetmY() * tileHeight) - camOffsetY;
			offset.left = (tiles->operator[](j)->GetmX() * tileWidth) - camOffsetX;
			offset.bottom = offset.top + tileHeight;
			offset.right = offset.left + tileWidth;
			//RECT diff;
			//if(IntersectRect(&diff, &offset, &CCamera::GetInstance()->GetCameraRect()))
			if(offset.right - camRect.left > 0 && camRect.right - offset.left > 0 &&
			   offset.bottom - camRect.top > 0 && camRect.bottom - offset.top > 0)
			{
				RECT temp;
				temp.top = tiles->operator[](j)->GetY() * tiles->operator[](j)->GetHeight();
				temp.left = tiles->operator[](j)->GetX() * tiles->operator[](j)->GetWidth();
				temp.bottom = temp.top + tiles->operator[](j)->GetHeight();
				temp.right = temp.left + tiles->operator[](j)->GetWidth();
				
				RECT check;
				check.top = tiles->operator[](j)->GetmY()  * tiles->operator[](j)->GetHeight();
				check.left = tiles->operator[](j)->GetmX() * tiles->operator[](j)->GetWidth();
				check.bottom = check.top + tiles->operator[](j)->GetHeight();
				check.right  = check.left + tiles->operator[](j)->GetWidth();
				RECT bait;
				if(tiles->operator[](j)->GetType() == 1)
				{
					for(unsigned int k = 0; k < teleporters.size(); k++)
					{
						if(!teleporters[k]->GetIsOpen())
						{
							if(IntersectRect(&bait, &check, &teleporters[k]->GetRect()))
							{
								CSGD_TextureManager::GetInstance()->Draw(imageID,
								(tiles->operator[](j)->GetmX() * tiles->operator[](j)->GetWidth()) - CCamera::GetInstance()->GetOffsetX(), 
								(tiles->operator[](j)->GetmY()  * tiles->operator[](j)->GetHeight()) - CCamera::GetInstance()->GetOffsetY(), 
								1.0f, 1.0f, &temp, 0.0f, 0.0f, 0.0f, D3DCOLOR_ARGB(255, 100, 0, 0));
							}
						}
						else
						{
								CSGD_TextureManager::GetInstance()->Draw(imageID,
							(tiles->operator[](j)->GetmX() * tiles->operator[](j)->GetWidth()) - CCamera::GetInstance()->GetOffsetX(), 
							(tiles->operator[](j)->GetmY()  * tiles->operator[](j)->GetHeight()) - CCamera::GetInstance()->GetOffsetY(), 
							1.0f, 1.0f, &temp);
						}
					}
				}
				else
				{
					CSGD_TextureManager::GetInstance()->Draw(imageID,
						(tiles->operator[](j)->GetmX() * tiles->operator[](j)->GetWidth()) - CCamera::GetInstance()->GetOffsetX(), 
						(tiles->operator[](j)->GetmY()  * tiles->operator[](j)->GetHeight()) - CCamera::GetInstance()->GetOffsetY(), 
						1.0f, 1.0f, &temp);
				}
				

				CSGD_Direct3D::GetInstance()->GetSprite()->Flush();
				tiles->operator[](j)->setdepth(i);
			}
		}
		
	}
	vector<CDoor*>* dor = getdoors();
	for(unsigned int i = 0; i < (*dor).size(); i++)
	{
		if((*dor)[i]->getopen())
		{
			
			(*dor)[i]->rendertiles();

		}
	}
}

void CNode::EnterNode()
{
	isActive = true;

	for(unsigned int i = 0; i < activeEnemies.size(); ++i)
	{
		ObjectManager::GetInstance()->AddObject(activeEnemies[i]);
	}

	for(unsigned int i = 0; i < teleporters.size(); ++i)
		ObjectManager::GetInstance()->AddObject(teleporters[i]);

	for(unsigned int i = 0; i < firewalls.size(); ++i)
		ObjectManager::GetInstance()->AddObject(firewalls[i]);
}

void CNode::ExitNode()
{
	isActive = false;

	for(unsigned int i = 0; i < activeEnemies.size(); ++i)
		ObjectManager::GetInstance()->RemoveObject(activeEnemies[i]);

	for(unsigned int i = 0; i < teleporters.size(); ++i)
		ObjectManager::GetInstance()->RemoveObject(teleporters[i]);

	for(unsigned int i = 0; i < firewalls.size(); ++i)
		ObjectManager::GetInstance()->RemoveObject(firewalls[i]);

	CSGP_EventSystem::GetInstance()->SendEvent("destroy.all.bullets");
	CSGP_EventSystem::GetInstance()->SendEvent("destroy.all.drops");
}

void CNode::HandleEvent(CEvent* pEvnt)
{
	if(pEvnt->GetEventID() == "enemy.death")
	{
		// Get the dead enemy
		CEnemy* deadEnemy = (CEnemy*)pEvnt->GetParam();

		// Loop through the active enemies and look for the dead enemy
		for(auto i = activeEnemies.begin(); i != activeEnemies.end(); ++i)
		{
			if(deadEnemy == (*i))
			{// dead enemy found
				// Remove the enemy from the ObjectManager
				ObjectManager::GetInstance()->RemoveObject(*i);
				// Remove the enemy from the list of active enemies
				activeEnemies.erase(i);
				break;
			}
		}
	}
	else if(pEvnt->GetEventID() == "num.enemies")
	{
		int effect = *(int*)(pEvnt->GetParam());

		switch(effect)
		{
		case -2:
			if(enemies.size() > 1)
				enemies[1]->SetHealth(0);
			// Yes, cascade.
		case -1:
			if(enemies.size())
				enemies[0]->SetHealth(0);
			break;
		case 2:
			if(enemies.size() > 1)
				enemies[1]->SetHealth(enemies[1]->GetMaxHealth()*2);
			// Yes, cascade
		case 1:
			if(enemies.size())
				enemies[0]->SetHealth(enemies[0]->GetMaxHealth()*2);
			break;
		}
	}
}


vector<CLayer*>* CNode::getlayers()
{
	return &layers;
}

vector<CTeleporter*>* CNode::getTeles()
{
	return &teleporters;
}

vector<console*>* CNode::getcons()
{
	return &consoles;
}

vector<CDoor*>* CNode::getdoors()
{
	return &doors;
}

void CNode::SetImageID(int ID)
{
	imageID = ID;
	if(doors.size() != 0)
	{
		for(unsigned int i = 0; i < doors.size(); i++)
		{
			doors[i]->setimage(ID);
		}
	}
}
